import tkinter as tk
from tkinter import filedialog, scrolledtext, messagebox
import subprocess
import json
import threading
import os
import sys
import time
from pathlib import Path

class FlaskServiceManager:
    def __init__(self, root):
        self.root = root
        self.root.title("Flask服务管理器")
        self.root.geometry("800x600")
        self.root.minsize(600, 400)
        
        # 设置中文字体
        self.font = ('SimHei', 10)
        
        # 初始化变量
        self.python_path = tk.StringVar()
        self.flask_app_path = tk.StringVar()
        self.flask_process = None
        self.log_buffer = []
        self.max_log_lines = 1000
        self.is_running = False
        
        # 配置文件路径
        self.config_path = Path.home() / ".flask_service_manager_config.json"
        
        # 创建界面
        self.create_widgets()
        
        # 加载配置
        self.load_config()
    
    def create_widgets(self):
        # 创建主框架
        main_frame = tk.Frame(self.root, padx=10, pady=10)
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # Python环境设置框架
        python_frame = tk.LabelFrame(main_frame, text="Python环境设置", padx=10, pady=10, font=self.font)
        python_frame.pack(fill=tk.X, pady=(0, 10))
        
        tk.Label(python_frame, text="Python路径:", font=self.font).grid(row=0, column=0, sticky=tk.W, pady=5)
        tk.Entry(python_frame, textvariable=self.python_path, width=50, font=self.font).grid(row=0, column=1, padx=5, pady=5)
        tk.Button(python_frame, text="浏览...", command=self.browse_python, font=self.font).grid(row=0, column=2, padx=5, pady=5)
        
        # Flask应用设置框架
        flask_frame = tk.LabelFrame(main_frame, text="Flask应用设置", padx=10, pady=10, font=self.font)
        flask_frame.pack(fill=tk.X, pady=(0, 10))
        
        tk.Label(flask_frame, text="Flask应用路径:", font=self.font).grid(row=0, column=0, sticky=tk.W, pady=5)
        tk.Entry(flask_frame, textvariable=self.flask_app_path, width=50, font=self.font).grid(row=0, column=1, padx=5, pady=5)
        tk.Button(flask_frame, text="浏览...", command=self.browse_flask, font=self.font).grid(row=0, column=2, padx=5, pady=5)
        
        # 控制按钮框架
        control_frame = tk.Frame(main_frame)
        control_frame.pack(fill=tk.X, pady=(0, 10))
        
        self.start_button = tk.Button(control_frame, text="启动服务", command=self.start_flask, font=self.font, bg="#4CAF50", fg="white")
        self.start_button.pack(side=tk.LEFT, padx=(0, 10))
        
        self.stop_button = tk.Button(control_frame, text="停止服务", command=self.stop_flask, font=self.font, bg="#F44336", fg="white", state=tk.DISABLED)
        self.stop_button.pack(side=tk.LEFT)
        
        # 状态显示
        self.status_var = tk.StringVar(value="状态: 未运行")
        self.status_label = tk.Label(control_frame, textvariable=self.status_var, font=self.font, fg="red")
        self.status_label.pack(side=tk.RIGHT, padx=10)
        
        # 日志显示框架
        log_frame = tk.LabelFrame(main_frame, text="运行日志", padx=10, pady=10, font=self.font)
        log_frame.pack(fill=tk.BOTH, expand=True)
        
        self.log_text = scrolledtext.ScrolledText(log_frame, wrap=tk.WORD, font=self.font)
        self.log_text.pack(fill=tk.BOTH, expand=True)
        
        # 菜单
        menubar = tk.Menu(self.root)
        filemenu = tk.Menu(menubar, tearoff=0)
        filemenu.add_command(label="保存配置", command=self.save_config, accelerator="Ctrl+S")
        filemenu.add_command(label="重置配置", command=self.reset_config)
        filemenu.add_separator()
        filemenu.add_command(label="退出", command=self.root.quit)
        menubar.add_cascade(label="文件", menu=filemenu)
        
        helpmenu = tk.Menu(menubar, tearoff=0)
        helpmenu.add_command(label="关于", command=self.show_about)
        menubar.add_cascade(label="帮助", menu=helpmenu)
        
        self.root.config(menu=menubar)
        
        # 绑定快捷键
        self.root.bind("<Control-s>", lambda event: self.save_config())
    
    def browse_python(self):
        path = filedialog.askopenfilename(
            title="选择Python解释器",
            filetypes=[("Python Executable", "python*.exe;python*"), ("All Files", "*.*")]
        )
        if path:
            self.python_path.set(path)
    
    def browse_flask(self):
        path = filedialog.askopenfilename(
            title="选择Flask应用文件",
            filetypes=[("Python Files", "*.py"), ("All Files", "*.*")]
        )
        if path:
            self.flask_app_path.set(path)
    
    def load_config(self):
        try:
            if self.config_path.exists():
                with open(self.config_path, 'r', encoding='utf-8') as f:
                    config = json.load(f)
                    self.python_path.set(config.get('python_path', ''))
                    self.flask_app_path.set(config.get('flask_app_path', ''))
        except Exception as e:
            self.log(f"加载配置失败: {str(e)}")
    
    def save_config(self, event=None):
        try:
            config = {
                'python_path': self.python_path.get(),
                'flask_app_path': self.flask_app_path.get()
            }
            with open(self.config_path, 'w', encoding='utf-8') as f:
                json.dump(config, f, ensure_ascii=False, indent=2)
            self.log("配置已保存")
            return True
        except Exception as e:
            self.log(f"保存配置失败: {str(e)}")
            return False
    
    def reset_config(self):
        self.python_path.set('')
        self.flask_app_path.set('')
        if self.config_path.exists():
            try:
                os.remove(self.config_path)
                self.log("配置已重置")
            except Exception as e:
                self.log(f"删除配置文件失败: {str(e)}")
    
    def start_flask(self):
        # 检查配置
        if not self.python_path.get():
            messagebox.showerror("错误", "请设置Python环境路径")
            return
        
        if not self.flask_app_path.get():
            messagebox.showerror("错误", "请设置Flask应用路径")
            return
        
        # 保存配置
        self.save_config()
        
        # 准备命令
        cmd = [
            self.python_path.get(),
            self.flask_app_path.get()
        ]
        
        # 检查文件是否是Flask应用
        try:
            with open(self.flask_app_path.get(), 'r', encoding='utf-8') as f:
                content = f.read()
                if 'Flask(__name__)' not in content:
                    if messagebox.askyesno("确认", "所选文件似乎不是Flask应用，是否继续启动？"):
                        pass
                    else:
                        return
        except Exception as e:
            self.log(f"检查Flask应用失败: {str(e)}")
        
        # 禁用启动按钮，启用停止按钮
        self.start_button.config(state=tk.DISABLED)
        self.stop_button.config(state=tk.NORMAL)
        self.status_var.set("状态: 正在启动...")
        self.status_label.config(fg="orange")
        self.is_running = True
        
        # 清空日志
        self.log_text.delete(1.0, tk.END)
        self.log("正在启动Flask服务...")
        
        # 在新线程中启动Flask
        threading.Thread(target=self._run_flask, args=(cmd,), daemon=True).start()
    
    def _run_flask(self, cmd):
        try:
            # 设置环境变量
            env = os.environ.copy()
            env['FLASK_APP'] = self.flask_app_path.get()
            env['FLASK_DEBUG'] = '1'
            
            # 启动Flask进程
            self.flask_process = subprocess.Popen(
                cmd,
                stdout=subprocess.PIPE,
                stderr=subprocess.STDOUT,
                env=env,
                universal_newlines=True,
                bufsize=1
            )
            
            # 读取输出
            for line in iter(self.flask_process.stdout.readline, ''):
                self.log(line.strip())
                if not self.is_running:
                    break
            
            # 等待进程结束
            self.flask_process.wait()
            
            # 更新状态
            if self.is_running:
                self.log("Flask服务已停止")
                self.root.after(0, self._update_status_after_stop)
        except Exception as e:
            self.log(f"启动Flask服务失败: {str(e)}")
            self.root.after(0, self._update_status_after_stop)
    
    def _update_status_after_stop(self):
        self.start_button.config(state=tk.NORMAL)
        self.stop_button.config(state=tk.DISABLED)
        self.status_var.set("状态: 未运行")
        self.status_label.config(fg="red")
        self.is_running = False
        self.flask_process = None
    
    def stop_flask(self):
        if self.flask_process and self.is_running:
            self.log("正在停止Flask服务...")
            self.status_var.set("状态: 正在停止...")
            self.status_label.config(fg="orange")
            
            # 尝试优雅地停止
            try:
                self.flask_process.terminate()
                # 等待一段时间
                for i in range(10):
                    if self.flask_process.poll() is not None:
                        break
                    time.sleep(0.1)
                else:
                    # 如果还没停止，强制杀死
                    self.flask_process.kill()
                    self.log("已强制终止Flask服务")
            except Exception as e:
                self.log(f"停止Flask服务失败: {str(e)}")
            
            self._update_status_after_stop()
    
    def log(self, message):
        # 添加到日志缓冲区
        self.log_buffer.append(message)
        # 限制缓冲区大小
        if len(self.log_buffer) > self.max_log_lines:
            self.log_buffer = self.log_buffer[-self.max_log_lines:]
        
        # 在UI线程中更新日志显示
        self.root.after(0, self._update_log_display)
    
    def _update_log_display(self):
        # 清空并重新显示所有日志
        self.log_text.delete(1.0, tk.END)
        for line in self.log_buffer:
            self.log_text.insert(tk.END, line + '\n')
        # 滚动到底部
        self.log_text.see(tk.END)
    
    def show_about(self):
        messagebox.showinfo(
            "关于",
            "Flask服务管理器 v1.0\n\n"
            "一个简单的Flask应用管理工具，可从配置文件加载Python环境，\n"
            "设置Flask应用路径，并通过界面启动和停止服务，查看运行日志。"
        )

if __name__ == "__main__":
    # 确保中文显示正常
    if sys.platform.startswith('win'):
        # Windows系统
        os.environ['PYTHONIOENCODING'] = 'utf-8'
    
    root = tk.Tk()
    app = FlaskServiceManager(root)
    root.mainloop()    